package cn.ecasoft.util;


import cn.ecasoft.constant.ColType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Random;

/**
 * @author yangsen
 * @date 2021/4/26 17:20
 */
@Component
public class EncryptUtil {
    /**
     * 生成签名
     * <p>
     * 使用md5加密
     *
     * @param value 明文
     * @return 签名
     * @throws Exception
     */
    public static String getMD5_HEX(String value) {

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(value.getBytes(StandardCharsets.UTF_8));
            return DigestHelper.byte2hex(md.digest());
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    private static Logger log = LoggerFactory.getLogger(EncryptUtil.class);

    private static Base64.Decoder decoder;

    private static Base64.Encoder encoder;



    static {
        decoder = Base64.getDecoder();
        encoder = Base64.getEncoder();
    }



    public static String getSixteenBitString(){
        StringBuffer sb = new StringBuffer();
        String[] chars = new String[]{
                "1","2","3","4","5","6","7","8","9","a","b",
                "c","d","e","f","g","h","i","j","k","l","m",
                "n","o","p","q","r","s","t","u","v","w","x",
                "y","z","A","B","C","D","E","F","G","H","I",
                "J","K","L","M","N","O","P","Q","R","S","T",
                "U","V","W","X","Y","Z",
        };
        int len = chars.length;
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(chars[random.nextInt(len-1)]);
        }
        return sb.toString();

    }



    /**
     * AES加密
     * @param data
     * @param key
     * @param iv
     * @return
     * @throws Exception
     */
    public static String encrypt_HEX_AES_CBC(String data,String key,String iv) {
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();
            //如果不足16位，加0
            StringBuilder plainText = new StringBuilder(data);
            int length = plainText.length();
            if(length%16!=0){
                for (int i = 0; i < 16-(length%16) ; i++) {
                    plainText.append("0");
                }
            }
            byte[] dataBytes = plainText.toString().getBytes();
            int dataLength = dataBytes.length;
            if (dataLength % blockSize != 0) {
                dataLength = dataLength + (blockSize - (dataLength % blockSize));
            }
            byte[] plaintext = new byte[dataLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
            byte[] bytes = cipher.doFinal(plaintext);
//            return byte2hex(encoder.encodeToString(bytes).getBytes(StandardCharsets.UTF_8));
            return byte2hex(bytes);

        }catch (Exception e) {
            log.error("AES加密失败");
            log.error(e.getMessage());

        }

        return null;

    }

    /**
     * AES解密
     * @param data
     * @param key
     * @param iv
     * @return
     * @throws Exception
     */
    public static String decrpty_HEX_AES_CBC(String data,String key,String iv){
        try {
            //如有空格、替换空格
            byte[] bytes = hex2bytes(data.replace(" ",""));
//            byte[] decode = decoder.decode(bytes);
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
            byte[] plainByte = cipher.doFinal(bytes);
            return new String(plainByte).trim();
        }catch (Exception e){
            log.error("AES解密失败");
            log.error(e.getMessage());
        }

        return null;
    }


    /**
     * AES加密
     * @param data
     * @return
     * @throws Exception
     */
    public static String encryptAES_ECB(String data,String key) throws Exception{
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
        int blockSize = cipher.getBlockSize();
        byte[] dataBytes = data.getBytes();
        int dataLength = dataBytes.length;
        if(dataLength % blockSize != 0){
            dataLength = dataLength + (blockSize - (dataLength % blockSize));
        }
        byte [] plaintext = new byte[dataLength];
        System.arraycopy(dataBytes,0,plaintext,0,dataBytes.length);
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(),"AES");
        cipher.init(Cipher.ENCRYPT_MODE,secretKey);
        byte[] bytes = cipher.doFinal(plaintext);
        return encoder.encodeToString(bytes);


    }

    /**
     * AES解密
     * @param data
     * @return
     * @throws Exception
     */
    public static String decrptyAES_ECB(String data,String key) throws Exception{
        byte[] bytes = decoder.decode(data);
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(),"AES");
        cipher.init(Cipher.DECRYPT_MODE,secretKey);
        byte[] plainByte = cipher.doFinal(bytes);
        return new String(plainByte).trim();
    }



    public static void main(String[] args) throws Exception{
        String data = "[{\"M_Type\":\"notify\",\"M_Code\":\"3301012201201001004\"}]";
//        String data ="[{\"M_Type\":\"auth_ack\",\"M_Code\":\"3301012201201001004\",\"M_Value\":\"a5f6ba429eb7400141f21e94d7eb3e50\"}]";
        String s = encrypt_HEX_AES_CBC(data, ColType.key,ColType.iv);
        String re="";
        for (int i = 0; i < s.length(); i++) {
            if(i%2==0){
                re+=s.charAt(i);
            }else{
                re+=s.charAt(i)+" ";
            }
        }
        System.out.println(s);
        System.out.println("55 AA 55 AA 94 00 00 00 00 00 00 00 "+re+"68 68 16 16");

//        String yuan= UUID.randomUUID().toString()+miyao;
//        System.out.println(yuan);
    }

    public static void main1(String[] args) {
        String s= "3a8cc8fa888f49ffa5a07f9b75000a1aIJKLMZOPQRKTUVWJ";
        System.out.println(getMD5_HEX(s));
    }

    /***
     * 将byte[]转成16进制字符串
     *
     * @param data
     *
     * @return 16进制字符串
     */
    public static String byte2hex(byte[] data) {
        StringBuilder hash = new StringBuilder();
        String stmp;
        for (int n = 0; data != null && n < data.length; n++) {
            stmp = Integer.toHexString(data[n] & 0XFF);
            if (stmp.length() == 1)
                hash.append('0');
            hash.append(stmp);
        }
        return hash.toString();
    }

    public static byte[] hex2bytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }
    /**
     * Convert char to byte
     * @param c char
     * @return byte
     */
    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }
}
